package com.dnb.webmash.playmaker.client.ui;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;

import com.dnb.webmash.playmaker.client.AppConstants;
import com.dnb.webmash.playmaker.client.ClientFieldVerifier;
import com.dnb.webmash.playmaker.client.LoginService;
import com.dnb.webmash.playmaker.client.LoginServiceAsync;
import com.dnb.webmash.playmaker.client.UniqueTreeItem;
import com.dnb.webmash.playmaker.client.WebPlaylistService;
import com.dnb.webmash.playmaker.client.WebPlaylistServiceAsync;
import com.dnb.webmash.playmaker.client.mediaplayer.MediaPlayersManager;
import com.dnb.webmash.playmaker.shared.LoginInfo;
import com.dnb.webmash.playmaker.shared.MyURL;
import com.dnb.webmash.playmaker.shared.PlaylistItem;
import com.dnb.webmash.playmaker.shared.Utility;
import com.google.appengine.api.datastore.Text;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.HorizontalSplitPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.RichTextArea;

@SuppressWarnings("deprecation")
public class WatchTab extends Composite { //TODO USE CELLLIST TO FIX GLITCHES ON TREE
	private static final AppConstants CONSTANTS = GWT.create(AppConstants.class);	
	private final WebPlaylistServiceAsync webPlaylistService = GWT.create(WebPlaylistService.class);
	private final LinkedHashMap<TreeItem, PlaylistItem> playlistItems = new LinkedHashMap<TreeItem, PlaylistItem>(); 
	private final LinkedHashMap<UniqueTreeItem, PlaylistItem> playableItems = new LinkedHashMap<UniqueTreeItem, PlaylistItem>();
	private final LinkedHashMap<TreeItem, TreeItem> nowPlayingItems = new LinkedHashMap<TreeItem, TreeItem>();
	private final LinkedHashMap<MyURL, TreeItem> requestedURLS = new LinkedHashMap<MyURL, TreeItem>();
	private int index = -1, rereqIndex = 0; 
	private static final int comboboxMax = 21, internalReqDepthMax = 1; //first one is the lazy loading depth, second is fixed internal recursion depth.
	private MediaPlayersManager mediaPlayersManager;
	private final Tree tree = new Tree();
	private final TreeItem nowPlaying = new TreeItem(CONSTANTS.nowPlaying_html());
	private final Label errorLabel = new Label();	
	private final Label itemInfoLbl = new Label();
	final Button getChanButton = new Button(CONSTANTS.getChanButton_html());
	private ListBox comboBox = new ListBox();
	private LoginInfo loginInfo = null;
	private Anchor signInLink = new Anchor("Sign in");
	private Anchor signOutLink = new Anchor("Sign out");	
	private boolean isLoggedIn = false;
	protected Boolean requestMediaOnly = true, internalZeroRec = true; //default to only media and quick request
	private String requestID;

	public WatchTab(){
		/*
		 * WATCH TAB
		 */
		final DockLayoutPanel tab0_watchDockLayoutPanel = new DockLayoutPanel(Unit.EM);

		// Create a handler for the nextButton
		class NextButtonHandler implements ClickHandler, KeyUpHandler {

			@Override
			public void onKeyUp(KeyUpEvent event) {
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER)
					WatchTab.this.playPrevNextMedia(1);
			}

			@Override
			public void onClick(ClickEvent event) {
				WatchTab.this.playPrevNextMedia(1);
			}
		}
		// Create a handler for the nextButton
		class PrevButtonHandler implements ClickHandler, KeyUpHandler {

			@Override
			public void onKeyUp(KeyUpEvent event) {
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER)
					WatchTab.this.playPrevNextMedia(-1);
			}

			@Override
			public void onClick(ClickEvent event) {
				WatchTab.this.playPrevNextMedia(-1);
			}
		}

		final NextButtonHandler handlNext = new NextButtonHandler();
		final PrevButtonHandler handlPrev = new PrevButtonHandler();

		final HorizontalPanel inputControlsPanel = new HorizontalPanel();
		inputControlsPanel.setSpacing(2);
		tab0_watchDockLayoutPanel.addNorth(inputControlsPanel, 2.5);

		final TextBox textBox = new TextBox();
		textBox.setTitle(CONSTANTS.textBox_title());
		inputControlsPanel.add(textBox);
		textBox.setWidth(CONSTANTS.textBox_width());//TODO FIX NOT SHOWING UP
		textBox.setFocus(true);
		textBox.selectAll();

		for (int i=0; i < comboboxMax; i++) comboBox.addItem(i+"");
		comboBox.setTitle(CONSTANTS.comboBox_title());
		inputControlsPanel.add(comboBox);

		CheckBox requestOnlyMedia_checkBox = new CheckBox();
		requestOnlyMedia_checkBox.setTitle(CONSTANTS.checkBox_title());
		requestOnlyMedia_checkBox.setValue(this.requestMediaOnly);
		inputControlsPanel.add(requestOnlyMedia_checkBox);
		requestOnlyMedia_checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
			@Override
			public void onValueChange(ValueChangeEvent<Boolean> event) {
				WatchTab.this.requestMediaOnly = event.getValue();
			}
		});

		CheckBox enableInternalRec = new CheckBox();
		enableInternalRec.setTitle(CONSTANTS.simpleCheckBox_title_1());
		enableInternalRec.setValue(this.internalZeroRec);
		inputControlsPanel.add(enableInternalRec);
		enableInternalRec.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
			@Override
			public void onValueChange(ValueChangeEvent<Boolean> event) {
				WatchTab.this.internalZeroRec = event.getValue();
			}
		});

		getChanButton.setTitle(CONSTANTS.getChanButton_title());
		inputControlsPanel.add(getChanButton);
		getChanButton.setText(CONSTANTS.getChanButton_text());
		getChanButton.addStyleName("getChannelButton");

		Button btnPrev = new Button(CONSTANTS.btnPrev_html());
		btnPrev.setTitle(CONSTANTS.btnPrev_title());
		inputControlsPanel.add(btnPrev);
		// getChanButton.setWidth(60+"px");

		final Button btnNext = new Button(CONSTANTS.btnNext_html());
		btnNext.setTitle(CONSTANTS.btnNext_title());
		inputControlsPanel.add(btnNext);

		Button btnSave = new Button(CONSTANTS.btnSave_html());
		btnSave.addKeyUpHandler(new KeyUpHandler() {
			public void onKeyUp(KeyUpEvent event) {
				if (WatchTab.this.isLoggedIn){
					if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER){
						TreeItem sel = tree.getSelectedItem();
						//Verify this was one of the requested URLS and not a system-owned node (cant save those)
						if (playableItems.containsKey(sel)||requestedURLS.containsValue(sel)){
							PlaylistItem plsit = WatchTab.this.getPlaylistItemFromTreeItem(sel);
							WatchTab.this.requestSavePlsToServer(plsit);
						}
						else errorLabel.setText("Can only save requested playlists or media items");
					}
				} else errorLabel.setText("Not logged in - cannot save.");
			}
		});
		btnSave.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				if (WatchTab.this.isLoggedIn){
					TreeItem sel = tree.getSelectedItem();
					//Verify this was one of the requested URLS and not a system-owned node (cant save those)
					if (playableItems.containsKey(sel)||requestedURLS.containsValue(sel)){
						PlaylistItem plsit = WatchTab.this.getPlaylistItemFromTreeItem(sel);
						WatchTab.this.requestSavePlsToServer(plsit);
					}
					else errorLabel.setText("Can only save requested playlists or media items");
				} else errorLabel.setText("Not logged in - cannot save.");
			}
		});
		btnSave.setTitle("Saves the selected playlist so that you can continue watching next time you log back in - Warning, overrides previous saved sessions.");
		inputControlsPanel.add(btnSave);

		Button btnLoad = new Button(CONSTANTS.btnLoad_html());
		btnLoad.setTitle(CONSTANTS.btnLoad_title());
		btnLoad.addKeyUpHandler(new KeyUpHandler() {
			public void onKeyUp(KeyUpEvent event) {
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER){
					WatchTab.this.requestLoadPlsFromServer();
				}
			}
		});
		btnLoad.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				WatchTab.this.requestLoadPlsFromServer();
			}
		});
		inputControlsPanel.add(btnLoad);

		// Set up login link for signin
		// Check login status using login service.
		LoginServiceAsync loginService = GWT.create(LoginService.class);
		loginService.login(GWT.getHostPageBaseURL(), new AsyncCallback<LoginInfo>() {
			public void onFailure(Throwable error) {
				errorLabel.setText("Unable to verify login status.");
			}	      
			public void onSuccess(LoginInfo result) {
				loginInfo = result;
				if(loginInfo.isLoggedIn()) {
					signOutLink.setHref(loginInfo.getLogoutUrl());
					inputControlsPanel.add(signOutLink);
					WatchTab.this.isLoggedIn = true;
					//Auto load the current users last session
					WatchTab.this.requestLoadPlsFromServer();

					//only show these items if the logged in user is admin
					if (loginInfo.isAdmin()){
						itemInfoLbl.setVisible(true);
						//Load the global playlist for admins
						WatchTab.this.requestLoadGlobalPlsFromServer();
					}
					else
						itemInfoLbl.setVisible(false);
				} else {
					signInLink.setHref(loginInfo.getLoginUrl());
					inputControlsPanel.add(signInLink);	
					WatchTab.this.isLoggedIn = false;
					//hide admin only things if not logged in
					itemInfoLbl.setVisible(false);
				}
			}
		});

		// Create a handler for the sendButton and nameField
		class GetChanButtonHandler implements ClickHandler, KeyUpHandler {
			/**
			 * Fired when the user clicks on the sendButton.
			 */
			public void onClick(ClickEvent event) {
				this.sendURLToServer();
			}

			/**
			 * Fired when the user types in the nameField.
			 */
			public void onKeyUp(KeyUpEvent event) {
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER)
					this.sendURLToServer();
			}

			/**
			 * Send the name from the nameField to the server and wait for a
			 * response.
			 */
			private void sendURLToServer() {
				final String textToServer = textBox.getText();
				WatchTab.this.requestPlaylistFromServer(textToServer);
			}
		}

		// HANDLERS::
		// Add a handler to send the name to the server
		final GetChanButtonHandler handler = new GetChanButtonHandler();

		btnNext.addClickHandler(handlNext);
		btnNext.addKeyUpHandler(handlNext);
		btnPrev.addClickHandler(handlPrev);
		btnPrev.addKeyUpHandler(handlPrev);
		getChanButton.addClickHandler(handler);
		textBox.addKeyUpHandler(handler);

		HorizontalPanel southHorizontalCommentsPanel = new HorizontalPanel();
		tab0_watchDockLayoutPanel.addSouth(southHorizontalCommentsPanel, 4.0);
		southHorizontalCommentsPanel.setSize("100%", "100%");

		RichTextArea commentsTA = new RichTextArea();//TODO replace this with: checkbox menu to 'tag'
		// OR chat or comment area or both (toggle)?
		southHorizontalCommentsPanel.add(commentsTA);//TODO IMPLEMENT USE AND LOADING/SAVING TO PLAYLISTITEM
		commentsTA.setWidth("100%");

		HorizontalSplitPanel playerPlaylistSplitPanel = new HorizontalSplitPanel();
		tab0_watchDockLayoutPanel.add(playerPlaylistSplitPanel);
		playerPlaylistSplitPanel.setSize("100%","100%");

		// Add the textbox and treenode viewer
		final VerticalPanel playlistPanel = new VerticalPanel();
		playlistPanel.add(this.errorLabel);

		// ADDING THE TREE
		this.nowPlaying.setVisible(false);
		tree.setAnimationEnabled(false);
		playlistPanel.add(tree);
		playlistPanel.setCellHeight(tree, "100%");
		playlistPanel.setCellWidth(tree, "100%");
		tree.setSize("100%", "70%");
		this.tree.addItem(this.nowPlaying);		
		itemInfoLbl.setVisible(false);
		playlistPanel.add(itemInfoLbl);

		playerPlaylistSplitPanel.setLeftWidget(playlistPanel);
		playlistPanel.setSize("100%", "100%");
		/*TREE SCROLL FIX
			DOM.setStyleAttribute(this.tree.getElement(), "position", "static");
			this.tree.addFocusHandler(new FocusHandler() {
				@Override
				public void onFocus(FocusEvent event) {
					return;
				}
			});
		 */// END TREE SCROLL FIX

		this.tree.addSelectionHandler(new SelectionHandler<TreeItem>() {
			public void onSelection(SelectionEvent<TreeItem> event) {
				final TreeItem sel = event.getSelectedItem();								
				PlaylistItem plsit = getPlaylistItemFromTreeItem(sel);				
				if (plsit!=null){								
					WatchTab.this.itemInfoLbl.setText(plsit.toPrettyString()); //TODO MAYBE ADD A COMMENTS SECTION THAT THE USER CAN EDIT NEAR THIS UI
					if (plsit.isPlayable())
						WatchTab.this.embedPlsItem(plsit);
				}
				else
					WatchTab.this.itemInfoLbl.setText("No PlaylistItem linked to selected TreeItem!");
			}
		});
		this.tree.addKeyUpHandler(new KeyUpHandler() {
			@Override
			public void onKeyUp(KeyUpEvent event) {
				String url;
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
					final TreeItem sel = WatchTab.this.tree.getSelectedItem();
					PlaylistItem plsit = WatchTab.this.getPlaylistItemFromTreeItem(sel);
					if (!plsit.isPlayable()) {						
						url = sel.getText();
						if (ClientFieldVerifier.isValidURL(url)) {
							textBox.setText(url);
							getChanButton.click();
						}else {
							if (ClientFieldVerifier.isValidURL(plsit.getFullURL())) {
								textBox.setText(plsit.getFullURL());
								getChanButton.click();
							}
						}
					} else
						WatchTab.this.embedPlsItem(plsit);					
				}
			}
		});

		// The universal media player
		this.mediaPlayersManager = new MediaPlayersManager();
		playerPlaylistSplitPanel.setRightWidget(mediaPlayersManager);
		mediaPlayersManager.setSize("100%", "100%");

		this.initWidget(tab0_watchDockLayoutPanel);
	}

	@Override
	public void setWidth(String width) {//TODO add to prefs
		mediaPlayersManager.setSize("100%", "100%");
		tree.setWidth("100%");
		super.setWidth(width);
	}
	@Override
	public void setHeight(String height) {
		super.setHeight(height);
	}
	/*
	 * End of Watch TAB
	 * Start of helpers
	 */
	/*
	 * Adds playlist to tree view and to the master playableItems list
	 * @returns the last TreeItem added to the tree
	 */
	private Boolean addPlaylist(ArrayList<PlaylistItem> vals, Tree tree, Label myLabel) {				
		TreeItem parent = null;
		Boolean addedSomething = false;
		for (int i = 0; i < vals.size(); i++) {//each one should be a playlist: a URL root with media and links within
			final PlaylistItem it = vals.get(i);
			if (requestedURLS.containsKey(it.getURL())){tree.removeItem(requestedURLS.get(it.getURL()));//remove the nodes about to be updated
			}
			parent = new TreeItem();
			parent.setText(it.getName());
			tree.addItem(parent);//add it
			this.playlistItems.put(parent,it);
			if (it.getURL()!=null) {this.requestedURLS.put(it.getURL(),parent);	//Remember the added playlists								
			}
			if (it.hasChildren()) { //did we find anything?
				addedSomething = true;
				this.addPlaylistNode(it.getChildren(), parent);
			} else {//empty								
				tree.removeItem(parent);
				if (myLabel!=null) myLabel.setText("No media in playlist: "+ it.getName());
			}
		}
		return addedSomething; //returns the last element added
	}

	// recursive helper method
	private void addPlaylistNode(LinkedHashSet<PlaylistItem> vals, TreeItem branch) {		//TODO HERE ADD CODE TO STORE A mini NOW PLAYING IN EACH REQUESTED NODE, WITH THEIR MEDIA ONLY
		Iterator<PlaylistItem> iter = vals.iterator();
		while (iter.hasNext()){
			PlaylistItem it = iter.next();
			if (it.hasChildren()) {
				TreeItem parent = new TreeItem();
				parent.setText(it.getName());
				branch.addItem(parent);
				this.playlistItems.put(parent, it);
				this.addPlaylistNode(it.getChildren(), parent);
			} else {
				final UniqueTreeItem ti = new UniqueTreeItem(it.getName());
				branch.addItem(ti);
				this.playlistItems.put(ti, it);
				if (it.isPlayable()) this.playableItems.put(ti, it);// has no children so could be playable item
			}
		}
	}

	private PlaylistItem getPlaylistItemFromTreeItem(TreeItem sel){
		PlaylistItem item = WatchTab.this.playlistItems.get(sel);
		if (item==null) {//might be in now playing
			final TreeItem nowPlaying = WatchTab.this.nowPlayingItems.get(sel);
			item = WatchTab.this.playableItems.get(nowPlaying);			
			// TODO add highlighting to now playing node using font color or css (leave tree.setSelected)
		}
		return item;
	}

	private boolean embedPlsItem(PlaylistItem sel) {
		if ((sel!=null) && (sel.isPlayable())){								
			return this.mediaPlayersManager.embedItem(sel);
		} else
			this.errorLabel.setText("Error embedding media!");
		return false;
	}

	//updates the now playing node
	private void updateAllMediaNode() {
		this.nowPlaying.removeItems();// clear
		this.nowPlayingItems.clear();
		final ArrayList<UniqueTreeItem> keys = new ArrayList<UniqueTreeItem>(this.playableItems.keySet());
		for (int i = 0; i < keys.size(); i++) {
			TreeItem it = new TreeItem();
			it.setText(keys.get(i).getText());
			this.nowPlayingItems.put(it, keys.get(i));
			this.nowPlaying.addItem(it);
		}
		if (!keys.isEmpty()){
			this.nowPlaying.setVisible(true);
			if (mediaPlayersManager.getCurrentPlayer()==null){
				playPrevNextMedia(1);// load next
			}
		}
		else this.nowPlaying.setVisible(false);
	}

	// Cycles the index counter for the playableItems counter
	private void playPrevNextMedia(int dir) {
		if (dir >0)
		{	
			if (this.index < this.playableItems.size()-1)
				this.index++;
			else
				this.index = 0;

		}
		else
		{
			if (this.index > 0)
				this.index--;
			else
				this.index = this.playableItems.size()-1;
		}
		final ArrayList<UniqueTreeItem> keys = new ArrayList<UniqueTreeItem>(this.playableItems.keySet());
		this.tree.setSelectedItem(keys.get(this.index), true);
	}

	/****************************************************************************************************************
	 * 
	 * Start of RPC calling methods
	 ****************************************************************************************************************/
	private void requestPlaylistFromServer(String urlToServer)	throws IllegalArgumentException {
		urlToServer = urlToServer.trim();
		this.errorLabel.setText("");
		this.getChanButton.setEnabled(false);
		if (!ClientFieldVerifier.isValidURL(urlToServer)) {
			// CHECK TO SEE IF HTTP: IS MISSING
			final String pref = "http://" + urlToServer;
			if (!ClientFieldVerifier.isValidURL(pref)) { // MyURL IS STILL BAD
				this.errorLabel.setText("Please enter a valid MyURL");
				// TODO never reaches this due to having prepended http://, add	another check besides isValidURL
				return;
			} else
				urlToServer = pref;
		}		
		final int internalLevel;
		if (this.internalZeroRec) internalLevel= 0;
		else internalLevel = WatchTab.internalReqDepthMax;
		this.requestID = Utility.generateRequestID();
		final String urlTS = urlToServer; 
		this.webPlaylistService.requestDoc(urlTS, new AsyncCallback<Text>() {
			
			@Override
			public void onSuccess(Text result) {
				// TODO ADD THE OTHER STEPS HERE
				requestlaylist(urlTS, internalLevel, result);
			}
			
			@Override
			public void onFailure(Throwable caught) {
				errorLabel.setText("Failed to Request Doc!");
			}
		});
			errorLabel.setText("Requesting Doc...");
	}
	protected void requestlaylist(String urlToServer, int internalLevel, Text docText) {
		this.webPlaylistService.requestPlaylist(urlToServer, internalLevel, requestMediaOnly, this.requestID, docText, null, //TODO CHANGE NULL TO A LIST OF MEDIATYPES
				new AsyncCallback<PlaylistItem>() {
			public void onFailure(Throwable caught) {
				// Show the RPC error message to the user
				WatchTab.this.getChanButton.setEnabled(true);
				WatchTab.this.rereqIndex = 0;
				WatchTab.this.errorLabel.setText("There was an error on the server... please try again later.");
			}

			public void onSuccess(PlaylistItem result) {
				WatchTab.this.getChanButton.setEnabled(true);
				if (result!=null) {
					WatchTab.this.errorLabel.setText("");
					if (result.hasChildren()){
						ArrayList<PlaylistItem> resultHolder = new ArrayList<PlaylistItem>();
						resultHolder.add(result);
						boolean addedSomething = WatchTab.this.addPlaylist(resultHolder, WatchTab.this.tree, WatchTab.this.errorLabel);
						//verify whether we need to keep requesting
						if (WatchTab.this.comboBox.getSelectedIndex()>WatchTab.this.rereqIndex) WatchTab.this.reRequestFurtherPlaylist(result);
						else {//if this result had all empty children then rerequest anyways
							if (!addedSomething) WatchTab.this.reRequestFurtherPlaylist(result);
							else {//found something and request is not deeper
								WatchTab.this.rereqIndex = 0;
								if (!playableItems.isEmpty()) 
									updateAllMediaNode();
								//Store this URL and all media found in it to build the media db
								WatchTab.this.requestStoreMedias(new ArrayList<PlaylistItem>(playableItems.values()),result.getURL().toString());
							}
						}
					} else WatchTab.this.reRequestFurtherPlaylist(result);
				} else WatchTab.this.errorLabel.setText("No Media at URL... or Connection Failed"); //TODO RETRY WITH 0 LEVELS IF =NULL?
			}
		});
		if (WatchTab.this.requestMediaOnly)
			this.errorLabel.setText("Requesting Playlist...");
		else this.errorLabel.setText("Requesting Sitemap...");

	}

	protected void reRequestFurtherPlaylist(final PlaylistItem empty){
		if (comboBox.getSelectedIndex()<=0){
			this.errorLabel.setText("Nothing found, try increasing depth and re-requesting...");
			WatchTab.this.rereqIndex = 0;
			return;
		} else WatchTab.this.rereqIndex++;
		if (WatchTab.this.rereqIndex > comboBox.getSelectedIndex()){
			this.errorLabel.setText("Request ended.");
			WatchTab.this.rereqIndex = 0;
			return;
		}
		WatchTab.this.getChanButton.setEnabled(false);
		this.errorLabel.setText("Entering level "+WatchTab.this.rereqIndex+"...");
		if ((empty!=null)&&(empty.getURL()!=null)){
			this.webPlaylistService.resumeRecursion(empty, requestMediaOnly, this.requestID, null, null, new AsyncCallback<PlaylistItem>() { //THE FIRST NULL is for DOCTEXT, the second for MEDIATYPES

				@Override
				public void onFailure(Throwable caught) {
					// Show the RPC error message to the user
					WatchTab.this.errorLabel.setText("There was an error on the server... please try again later.");
					WatchTab.this.rereqIndex = 0;
					WatchTab.this.getChanButton.setEnabled(true);
				}
				@Override
				public void onSuccess(PlaylistItem result) {
					WatchTab.this.getChanButton.setEnabled(true);
					if (result!=null) {
						WatchTab.this.errorLabel.setText("");
						if (result.hasChildren()){
							ArrayList<PlaylistItem> resultHolder = new ArrayList<PlaylistItem>();
							resultHolder.add(result);
							WatchTab.this.addPlaylist(resultHolder, WatchTab.this.tree, WatchTab.this.errorLabel);
						}
					}
					//verify whether we need to keep requesting
					if (WatchTab.this.comboBox.getSelectedIndex()>WatchTab.this.rereqIndex) WatchTab.this.reRequestFurtherPlaylist(result);
					else {
						WatchTab.this.rereqIndex = 0;
						if (!playableItems.isEmpty()) 
							updateAllMediaNode();
						//Store this URL and all media found in it to build the media db
						WatchTab.this.requestStoreMedias(new ArrayList<PlaylistItem>(playableItems.values()),result.getURL().toString());
					}
				}
			});
		} else errorLabel.setText("null playlist! can't rerequest!");
		if (WatchTab.this.requestMediaOnly)
			this.errorLabel.setText("Requesting Playlist...");
		else this.errorLabel.setText("Requesting Sitemap...");
	}

	protected void requestLoadGlobalPlsFromServer(){//TODO add UI for this specific funct
		this.webPlaylistService.requestLoadGlobalPls(new AsyncCallback<PlaylistItem>() {
			@Override
			public void onFailure(Throwable caught) {
				WatchTab.this.errorLabel.setText("There was an error on the server... please try again later.");				
			}
			@Override
			public void onSuccess(PlaylistItem result) {
				if (result!=null&&(result.hasChildren())) {//has to have children to be properly loaded
					WatchTab.this.errorLabel.setText("");				
					ArrayList<PlaylistItem> resultHolder = new ArrayList<PlaylistItem>();
					resultHolder.add(result);
					if(!WatchTab.this.addPlaylist(resultHolder, WatchTab.this.tree, WatchTab.this.errorLabel))
						WatchTab.this.errorLabel.setText("Global Playlist Empty!");
					else {
						if (!playableItems.isEmpty()) {
							updateAllMediaNode();
						}
					}
				} else WatchTab.this.errorLabel.setText("Global Playlist Empty!");				
			}			
		});
	}
	protected void requestLoadPlsFromServer() {
		// TODO ONLY SEND RPC TO SERVER IF THIS IS FIRST TIME USER IS LOGGED ON AND NOTHING IS ON THE PLAYLIST?
		//FIGURE OUT USE CASE SCENARIO - WHEN DO WE REQUEST TO LOAD SAVED PLAYLISTS? DOES THIS NEED A LOAD BUTTON?
		if (this.isLoggedIn){//Load the previous session if logged in
			this.webPlaylistService.requestLoadCurUserPls(new AsyncCallback<PlaylistItem>() {
				@Override
				public void onFailure(Throwable caught) {
					// Show the RPC error message to the user
					WatchTab.this.errorLabel.setText("There was an error on the server... please try again later.");
				}
				@Override
				public void onSuccess(PlaylistItem result) {
					if ((result!=null)&&(result.hasChildren())) {//has to have children to be properly loaded
						WatchTab.this.errorLabel.setText("");				
						ArrayList<PlaylistItem> resultHolder = new ArrayList<PlaylistItem>();
						resultHolder.add(result);
						if (!WatchTab.this.addPlaylist(resultHolder, WatchTab.this.tree, WatchTab.this.errorLabel))
							WatchTab.this.errorLabel.setText("No Media Loaded");
						else {
							if (!playableItems.isEmpty()) {
								updateAllMediaNode();
							}
						}
					} else WatchTab.this.errorLabel.setText("No Media Loaded");				
				}
			});
			if (this.loginInfo.isAdmin())
				WatchTab.this.requestLoadGlobalPlsFromServer(); //Load the global playlist if admin is viewing
		}else WatchTab.this.errorLabel.setText("Not logged in - cannot load.");
	}
	/*
	 * Saves the passed playlist or all non-owned or pre-owned playlists if passed NULL.
	 */
	protected void requestSavePlsToServer(PlaylistItem savePlsit) {
		if (this.isLoggedIn){
			LinkedHashSet<PlaylistItem> toSave= new LinkedHashSet<PlaylistItem> ();			
			if (savePlsit==null){ // if not specified by caller save every requested URL
				for (TreeItem t : requestedURLS.values()){
					PlaylistItem svPls = WatchTab.this.getPlaylistItemFromTreeItem(t);
					if ((svPls.getOwner()==null)||(svPls.getOwner()==loginInfo.getUniqueID()))
						toSave.add(svPls);
				}
			} else toSave.add(savePlsit);
			boolean notAuth = false;
			for (PlaylistItem item : toSave){
				if ((item.getOwner()!=null)&&(item.getOwner()!=loginInfo.getUniqueID())){
					toSave.remove(item);
					notAuth = true;
				}
			}
			if (!toSave.isEmpty()){ 
				this.webPlaylistService.requestSaveUserPls(toSave, loginInfo, new AsyncCallback<Boolean>() {
					@Override
					public void onFailure(Throwable caught) {
						// TODO Auto-generated method stub
						WatchTab.this.errorLabel.setText("There was an error on the server... please try again later.");
					}

					@Override
					public void onSuccess(Boolean result) {
						if (result.booleanValue()) 
							WatchTab.this.errorLabel.setText("Saved successfully.");
						else WatchTab.this.errorLabel.setText("Unable to save... are you logged in?");				
					}
				});
			} else {
				if (notAuth)
					this.errorLabel.setText("Can't save this... owned by media-loop");
				else this.errorLabel.setText("Nothing to save!");
			}
		} else WatchTab.this.errorLabel.setText("Not logged in - cannot save.");
	}

	//Asks the server to store these medias if not already stored... nothing happens on success ?
	private void requestStoreMedias(ArrayList <PlaylistItem> plsToStore, String name) throws IllegalArgumentException{
		this.webPlaylistService.storeIfNotAlready(plsToStore,name, new AsyncCallback<Boolean>(){
			@Override
			public void onFailure(Throwable caught) {
				WatchTab.this.errorLabel.setText("There was an error on the server... please try again later.");
			}
			@Override
			public void onSuccess(Boolean result) {
				// TODO Auto-generated method stub
			}
		});
	}
}
